#include "NodeHandler.h"
#include "TaskExecutor.h"
#include "net_tool.h"
#include <iostream>
#include <string.h>
#include <thread>
#include <unistd.h>
#include <time.h>
#include "debug.h"
NodeHandler nodeHandler;

void NodeHandler::updateConfig() {
    this->master_addr = configReader.getConfig(CONFIG_MASTER_ADDR,"");
    this->master_port = atoi(configReader.getConfig(CONFIG_MASTER_PORT,"0").c_str());
    memset(this->master_ip, 0, sizeof(this->master_ip));
}

bool NodeHandler::updateHostCache() {
    if (isDomainName(this->master_addr.c_str())) {
        std::cout << "Resolve host\t:\t" << this->master_addr << std::endl;
        if (DNtoIP(this->master_addr.c_str(), this->master_ip) == false){
            std::string msg = "Unknow host name:\t" + this->master_addr;
            throw SocketException(msg);
        }
        std::cout << "Resolve result\t:\t" << this->master_ip << std::endl;
    } else {
        strcpy(this->master_ip, this->master_addr.c_str());
    }
    return true;
}

void NodeHandler::printInfo() {
    std::cout << "Remote master IP:" << this->master_ip << " port: " << this->master_port << std::endl;
}

socketinf NodeHandler::getMasterConnect() {
    try {
        if (!this->master_ip[0]) {
            this->updateHostCache();
        }
        DEBUG_PRINT("get a connect");
        return connect_to(this->master_ip, this->master_port, 10);
    } catch(const Exception& e) {
        memset(this->master_ip, 0, sizeof(this->master_ip));
        std::cerr << e.what() << std::endl;
        throw e;
    }
}

void NodeHandler::registerTask(unsigned char flag, ClientTaskExecutor *executor) {
    std::cout << "Register Task Flag:\t0x" << (unsigned int)flag << std::endl;
    if(this->taskMap.count(flag) == 1) {
        std::cerr << "[ERROR]Task flag '" << flag << "' existed" << std::endl;
        throw Exception("Task flag conflict");
    }
    this->taskMap[flag] = executor;
}
ClientTaskExecutor* NodeHandler::getClientTaskExecutor(unsigned char flag) {
    if(this->taskMap.count(flag) == 0) {
        throw Exception("Unknow task flag or task has no register");
    }
    return this->taskMap[flag];
}

void NodeHandler::executeClientTask(unsigned char flag, const char * arg, size_t len, bool sync) {
    std::thread th(&NodeHandler::ExecuteClientTaskCore, this, flag, arg, len);
    if (sync == true) {
        th.join();
    } else {
        th.detach();
    }
}

void NodeHandler::ExecuteClientTaskCore(unsigned char flag, const char * arg, size_t len) {
    socketinf sock;
    sock.socket_fd = -1;
    try {
        sock = this->getMasterConnect();
        int ret;
        ret = this->getClientTaskExecutor(flag)->clientAction(sock, arg, len);
        // if (ret == AUTO_CLOSE) {
            this->getClientTaskExecutor(TaskFlag::closetask)->clientAction(sock);
        // }
    } catch(const Exception& e) {
        if (sock.socket_fd != -1) sock.close();
        std::cerr << e.what() << '\n';
    }
    
    
}

SocketIO NodeHandler::launchTask(unsigned char taskFlag, const char * arg, size_t len) {
    SocketIO sio(this->getMasterConnect());
    sio.socketWriter->sendFrame(taskFlag, len);
    sio.socketWriter->write(arg, len);
    if (sio.socketReader->readFrame() == TaskStat::failed) {
        char buf[8192] = {0};
        sio.socketReader->read(buf, 8192);
        throw TaskFailedException(buf);
    }
    return sio;
}